package com.httpclient;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.SimpleHttpConnectionManager;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;

public class DefaultHttpClient implements IHttpClient {

    private HttpClient httpclient;

    private int max_bytes = 4096;

    private String lastExecuteUrl = "";

    private final int WAITING_CONNECT_TIME = 4000;

    private Cookie[] cookies;

    public DefaultHttpClient() {
        init();
    }

    /**
     * ��ʼ��
     */
    protected void init() {
        HttpConnectionManager connectionManager = new SimpleHttpConnectionManager(true);
        HttpConnectionManagerParams managerParams = new HttpConnectionManagerParams();
        managerParams.setConnectionTimeout(WAITING_CONNECT_TIME);
        managerParams.setSoTimeout(WAITING_CONNECT_TIME);
        connectionManager.setParams(managerParams);
        HttpClientParams httpClientParams = new HttpClientParams();
        httpClientParams.setConnectionManagerTimeout(WAITING_CONNECT_TIME);
        httpClientParams.setVersion(HttpVersion.HTTP_1_1);

//        Protocol oceanProtocol = new Protocol("https",
//                (ProtocolSocketFactory) new UncheckSecureProtocolSocketFactory(), 443);
//        Protocol.registerProtocol("https", oceanProtocol);
//        
        
        httpclient = new HttpClient(httpClientParams, connectionManager);
        httpclient.getParams().setParameter("http.protocol.content-charset", getEncoding());
        httpclient.getParams().setParameter("http.protocol.single-cookie-header", false);
        httpclient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
    }

    protected void requestInterceptor(HttpMethod method) {
        method.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;");
        method.setRequestHeader("Accept-Language", "zh-cn");
        // αװ�����������
        method.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
        method.setRequestHeader("Accept-Charset", getEncoding());
        method.setRequestHeader("Keep-Alive", "3000");
        method.setRequestHeader("Connection", "Keep-Alive");// close
        method.setRequestHeader("Cache-Control", "no-cache");
        method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        method.setRequestHeader("X-Forwarded-For","");
        
    }

    protected String getEncoding() {
        return "UTF-8";
    }

    public String doPost(String actionUrl, List<NameValuePair> params) throws IOException {
        return doPost(actionUrl, params, "");
    }

    public String doPost(String actionUrl, List<NameValuePair> params, String referer) throws IOException {
        NameValuePair[] paramsArray = new NameValuePair[params.size()];
        for (int i = 0; i < params.size(); ++i) {
            paramsArray[i] = params.get(i);
        }
        String responseContent = null;
        PostMethod method = new PostMethod(actionUrl);
        method.setRequestHeader("Referer", referer);
        requestInterceptor(method);
        method.setRequestBody(paramsArray);
        httpclient.executeMethod(method);
        lastExecuteUrl = method.getURI().toString();
        int statuscode = method.getStatusCode();
        if (HttpStatus.SC_MOVED_TEMPORARILY == statuscode || HttpStatus.SC_MOVED_PERMANENTLY == statuscode
                || HttpStatus.SC_SEE_OTHER == statuscode) {
            Header header = method.getResponseHeader("location");
            if (null != header) {
                String locationUrl = header.getValue();
                if (null == locationUrl || "".equals(locationUrl)) {
                    locationUrl = "/";
                }
                responseContent = doGet(toURIStr(locationUrl), referer);
            }
        } else {
            responseContent = getResponseBody(method.getResponseBodyAsStream(), method.getResponseCharSet());
        }
        cookies = httpclient.getState().getCookies();
        method.releaseConnection();
        return responseContent;
    }

    /**
     * 
     * @param urlStr
     * @return
     */
    private String toURIStr(String urlStr) {
        try {
            URL url = new URL(urlStr);
            URI uri = new URI(url.getProtocol(), url.getAuthority(), url.getHost(), url.getPort(), url.getPath(),
                    url.getQuery(), url.getRef());
            return uri.toString();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return urlStr;
    }

    private String getResponseBody(InputStream inputStream, String encode) throws IOException {
        byte[] b = new byte[max_bytes];
        StringBuilder builder = new StringBuilder();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int bytesRead = inputStream.read(b, 0, max_bytes);
        while (bytesRead != -1) {
            baos.write(b, 0, bytesRead);
            builder.append(new String(b, 0, bytesRead));
            bytesRead = inputStream.read(b, 0, max_bytes);
        }
        String content = baos.toString(getContentCharset(builder.toString(), encode));
        baos.close();
        return content;
    }

    public String doGet(String actionUrl, String referer) throws IOException {
        GetMethod method = new GetMethod(actionUrl);
        method.setRequestHeader("Referer", referer);
        httpclient.executeMethod(method);

        Header headers = method.getResponseHeader("ptvfsession");
        // �˴����Զ������ض���
        String responseContent = getResponseBody(method.getResponseBodyAsStream(), method.getResponseCharSet());
        lastExecuteUrl = method.getURI().toString();
        cookies = httpclient.getState().getCookies();
        method.releaseConnection();
        return responseContent;
    }

    public InputStream doGetForInputStream(String actionUrl, String referer) throws HttpException, IOException {
        GetMethod method = new GetMethod(actionUrl);
        method.setRequestHeader("Referer", referer);
        httpclient.executeMethod(method);
        cookies = httpclient.getState().getCookies();
        return method.getResponseBodyAsStream();
    }

    public HttpClient getHttpclient() {
        return httpclient;
    }

    /**
     * ���cookie
     * 
     * @param name
     * @param value
     * @param version
     * @param domain
     * @param path
     */
    public void addCookie(String name, String value, int version, String domain, String path) {
        Cookie cookie = new Cookie(domain, name, value);
        cookie.setDomain(domain);
        cookie.setVersion(version);
        cookie.setPath(path);
        httpclient.getState().addCookie(cookie);
    }

    public void logCookies() {
        Cookie[] cookies = httpclient.getState().getCookies();
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName() + "|" + cookie.getValue() + "|" + cookie.getPath() + "|"
                    + cookie.getDomain());
        }
    }

    public Cookie[] getCookies() {
        if (null == cookies) {
            return httpclient.getState().getCookies();
        }
        return cookies;
    }

    public String getLastExecuteUrl() {
        return lastExecuteUrl;
    }

    public void setLastExecuteUrl(String lastExecuteUrl) {
        this.lastExecuteUrl = lastExecuteUrl;
    }

    public void destroy() {
        if (null != httpclient.getHostConfiguration().getHost()) {
            ((SimpleHttpConnectionManager) httpclient.getHttpConnectionManager()).shutdown();
        }
    }

    private String getContentCharset(String content, String defaultEncode) {
        String charset = defaultEncode;
        if (matcherCharset(content, "(charset)\\s?=\\s?(utf-?8)")) {
            charset = "utf-8";
        } else if (matcherCharset(content, "(charset)\\s?=\\s?(gbk)")) {
            charset = "gbk";
        } else if (matcherCharset(content, "(charset)\\s?=\\s?(gb2312)")) {
            charset = "gb2312";
        }
        return charset;
    }

    public boolean matcherCharset(String s, String pattern) {
        Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE);
        Matcher matcher = p.matcher(s);
        if (matcher.find()) {
            return true;
        } else {
            return false;
        }
    }

}
